package com.example.mediademo.opengl;

import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLUtils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class BitmapDrawer implements IDrawder{

    /**
     * 纹理id
     */
    private int mTextureId = -1;
    /**
     * 顶点坐标
     */
    private float[] mVertexCoors = new float[]{-1f,-1f,1f,-1f,-1f,1f,1f,1f};
    /**
     * 纹理坐标
     */
    private float[] mTextureCoors = new float[]{0f,1f,1f,1f,0f,0f,1f,0f};
    /**
     * opelGl程序id
     */
    private int mProgram = -1;
    /**
     * 顶点坐标接收者
     */
    private int mVertexPosHandler = -1;
    /**
     * 纹理坐标接收者
     */
    private int mTexturePosHandler = -1;

    private FloatBuffer mVertexBuffer;

    private Bitmap mBitmap;

    private FloatBuffer mTextureBuffer;
    /**
     * 纹理接收者
     */
    private int textureHandler = -1;

    public BitmapDrawer(Bitmap bitmap) {
        mBitmap = bitmap;
        initPos();
    }

    /**
     * 初始化顶点坐标
     */
    private void initPos() {
        ByteBuffer bb = ByteBuffer.allocateDirect(mVertexCoors.length * 4);
        bb.order(ByteOrder.nativeOrder());
        // 将坐标数据转换为FloatBuffer,用来传入OpenGL ES程序
        mVertexBuffer = bb.asFloatBuffer();
        mVertexBuffer.put(mVertexCoors);
        mVertexBuffer.position(0);

        ByteBuffer bbTexure = ByteBuffer.allocateDirect(mTextureCoors.length * 4);
        bbTexure.order(ByteOrder.nativeOrder());
        mTextureBuffer = bbTexure.asFloatBuffer();
        mTextureBuffer.put(mTextureCoors);
        mTextureBuffer.position(0);
    }

    @Override
    public void setVideoSize(int w, int h) {

    }

    @Override
    public void setWindowSize(int w, int h) {

    }

    @Override
    public void draw() {
        if (mTextureId != -1) {
            //【步骤2: 创建、编译并启动OpenGL着色器】
            createGLPrg();
            // 3.激活并绑定纹理单元
            activateTexture();
            // 4.绑定图片到纹理单元
            bindBitmapToTexture();
            //【5.开始渲染绘制】
            doDraw();
        }
    }

    @Override
    public void setTextureID(int id) {
        this.mTextureId = id;
    }

    @Override
    public void release() {
        GLES20.glDisableVertexAttribArray(mVertexPosHandler);
        GLES20.glDisableVertexAttribArray(mTexturePosHandler);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        GLES20.glDeleteTextures(1, new int[]{mTextureId}, 0);
        GLES20.glDeleteProgram(mProgram);
    }

    @Override
    public void getSurfaceTexture(SurfaceTextureCallback surfaceTextureCallback) {

    }

    @Override
    public void setAlpha(float alpha) {

    }

    /**
     * 创建opengl程序
     */
    private void createGLPrg() {
        if (mProgram == -1) {
            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, getVertexShaderCode());
            int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, getFragmentShaderCode());

            //创建OpenGL ES程序，注意：需要在OpenGL渲染线程中创建，否则无法渲染
            mProgram = GLES20.glCreateProgram();
            //将顶点着色器加入到程序
            GLES20.glAttachShader(mProgram, vertexShader);
            //将片元着色器加入到程序中
            GLES20.glAttachShader(mProgram, fragmentShader);
            //连接到着色器程序
            GLES20.glLinkProgram(mProgram);

            mVertexPosHandler = GLES20.glGetAttribLocation(mProgram, "aPosition");
            mTexturePosHandler = GLES20.glGetAttribLocation(mProgram, "aCoordinate");
            //【注3：新增获取纹理接收者】
            textureHandler = GLES20.glGetUniformLocation(mProgram, "uTexture");
        }
        //使用OpenGL程序
        GLES20.glUseProgram(mProgram);
    }

    private void activateTexture() {
        //激活指定纹理单元
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        //绑定纹理ID到纹理单元
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
        //将激活的纹理单元传递到着色器里面
        GLES20.glUniform1i(textureHandler, 0);
        //配置纹理过滤模式
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, (float)GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, (float)GLES20.GL_LINEAR);
        // 配置纹理环绕方式
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    }

    private void bindBitmapToTexture() {
        if (!mBitmap.isRecycled()) {
            // 绑定图片到被激活的纹理单元
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0);
        }
    }


    private void doDraw() {
        //启用顶点的句柄
        GLES20.glEnableVertexAttribArray(mVertexPosHandler);
        GLES20.glEnableVertexAttribArray(mTexturePosHandler);
        //设置着色器参数 第二个参数表示一个顶点包含的数据数量，这里为xy，所以为2
        GLES20.glVertexAttribPointer(mVertexPosHandler, 2, GLES20.GL_FLOAT, false, 0, mVertexBuffer);
        GLES20.glVertexAttribPointer(mTexturePosHandler, 2, GLES20.GL_FLOAT, false, 0, mTextureBuffer);
        //开始绘制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    }


    /**
     * 加载着色器
     * @param type 着色器类别
     * @param shaderCode 着色器代码
     * @return
     */
    private int loadShader(int type , String shaderCode) {
        //根据type创建顶点着色器或者片元着色器
        int shader = GLES20.glCreateShader(type);
        //将资源加入到着色器中，并编译
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

    /**
     * 获取顶点着色器代码字符串
     * @return
     */
    private String getVertexShaderCode()  {
        return "attribute vec4 aPosition;" +
                "attribute vec2 aCoordinate;" +
                "varying vec2 vCoordinate;" +
                "void main() {" +
                "  gl_Position = aPosition;" +
                "  vCoordinate = aCoordinate;" +
                "}";
    }

    /**
     * 获取片元着色器代码字符串
     * @return
     */
    private String getFragmentShaderCode() {
//        RGBA
        return "precision mediump float;" +
                "uniform sampler2D uTexture;" +
                "varying vec2 vCoordinate;" +
                "void main() {" +
                "  vec4 color = texture2D(uTexture, vCoordinate);" +
                "  gl_FragColor = color;" +
                "}";
    }


}
